﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq.Expressions;
using System.Runtime.Serialization.Formatters.Binary;

namespace GwLib.UnitTesting
{
    public class TestStorage : ITestStorage
    {
        protected Dictionary<Type, object> _objectStores = new Dictionary<Type, object>();
        protected Func<object, object> _defaultCopyDelegate;

        public static object DeepSerializableObjectCopy(object obj)
        {
            using (var ms = new MemoryStream())
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(ms, obj);
                ms.Position = 0;

                return formatter.Deserialize(ms);
            }
        }
        
        public virtual IObjectStore<T> GetObjectStore<T>() where T : class, new()
        {
            var type = typeof(T);
            IObjectStore<T> objectStore = null;
            if (!_objectStores.ContainsKey(type))
            {
                objectStore = new ObjectStore<T>();
                if (_defaultCopyDelegate != null) objectStore.SetCopyImplementation(_defaultCopyDelegate);
                _objectStores[type] = objectStore;
            }
            else 
            {
                objectStore = _objectStores[type] as IObjectStore<T>;
            }
            return objectStore;
        }

        public void AddTrigger<T>(ObjectStoreTriggerType triggerType, Action<T, List<T>> trigger) where T : class, new()
        {
            GetObjectStore<T>().AddTrigger(triggerType, trigger);
        }

        public void SetDefaultCopyImplementation(Func<object, object> copyDelegate)
        {
            _defaultCopyDelegate = copyDelegate;
        }

        public void SetCopyImplementation<T>(Func<object, object> copyDelegate) where T : class, new()
        {
            GetObjectStore<T>().SetCopyImplementation(copyDelegate);
        }

        public void Reset()
        {
            foreach (var key in _objectStores.Keys)
            {
                dynamic objStore = _objectStores[key];
                objStore.Reset();
            }
        }

        public void Reset<T>() where T : class, new()
        {
            GetObjectStore<T>().Reset();
        }

        public int GetCount<T>() where T : class, new()
        {
            return GetObjectStore<T>().Count;
        }

        public T Insert<T>(T obj) where T : class, new()
        {
            return GetObjectStore<T>().Insert(obj);
        }

        public T UpdateWhere<T>(T obj, Func<T, bool> where) where T : class, new()
        {
            return GetObjectStore<T>().UpdateWhere(obj, where);
        }

        public T UpdateByColumn<T>(T obj, Expression<Func<T, object>> columnExpression) where T : class, new()
        {
            return GetObjectStore<T>().UpdateByColumn(obj, columnExpression);
        }

        public int DeleteWhere<T>(Func<T, bool> where) where T : class, new()
        {
            return GetObjectStore<T>().DeleteWhere(where);
        }

        public int DeleteByColumn<T>(T obj, Expression<Func<T, object>> columnExpression) where T : class, new()
        {
            return GetObjectStore<T>().DeleteByColumn(obj, columnExpression);
        }

        public T SelectOne<T>(Func<T, bool> where = null) where T : class, new()
        {
            return GetObjectStore<T>().SelectOne(where);
        }

        public List<T> SelectList<T>(Func<T, bool> where = null) where T : class, new()
        {
            return GetObjectStore<T>().SelectList(where);
        }
    }
}
